# (c) Simon J Galbraith 2007.
import java;
import javax
import cern
from cern.colt.matrix.DoubleFactory2D import *;
from cern.colt.matrix.impl import DenseDoubleMatrix2D;
try:
	from cern.colt.matrix.linalg import DoubleAlgebra as Algebra;
	from cern.jet.stat.DoubleDescriptive import *
	from cern.jet.stat.DoubleDescriptive import sum as vsum
	import cern.jet.math.DoubleFunctions as Functions
except:
	from cern.colt.matrix.linalg import Algebra;
	from cern.jet.stat.Descriptive import *
	from cern.jet.stat.Descriptive import sum as vsum
	import cern.jet.math.Functions as Functions

from org.python.core.exceptions import ValueError as PyValueException;
from cern.colt.matrix.doublealgo import Statistic;
from org.python.core import PyString,PyList,PyFloat,PyInteger,PySlice;
import cern;
import copy
import jarray


class MatrixTableModel(javax.swing.table.DefaultTableColumnModel):
	def __init__(self,table):
		self.table = table
		
	def moveColumn(y,ynew):
		pass

class MouseListenerTable(javax.swing.event.MouseInputAdapter):
	table = None
	
	def __init__(self,table,console):
		self.table = table
		self.console = console

	def mouseDragged(self,e):
		pass
	
	def mouseClicked(self,e):
		table=self.table
		
		if e.getClickCount() == 2:
			pass
		else:
			table = self.table
		  	column = table.columnAtPoint(e.getPoint());
		  	p = e.getPoint();
			row = table.rowAtPoint(p);
		  	if column == 0:
		  		table.setColumnSelectionAllowed(False);
		  		table.setRowSelectionAllowed(True);
		  		table.setRowSelectionInterval(row,row)
		  	else:
		  		table.setColumnSelectionAllowed(True);
				table.setRowSelectionAllowed(False);
				table.setColumnSelectionInterval(column,column)
				self.console.putVar({'refColumn':column})


class ViewMatrix(javax.swing.table.AbstractTableModel):
	def __init__(self,M):
		self._M = M
		self.columnNames=M.columnNames
		self.rowNames = M.rowNames
		self._name=M._name
		self.varname=M.varname
		
	def getColumnName(self, c):
		try:
			return self.columnNames[c]
		except:
			return None
	def getRowName(self, r):
			try:
				return self.rowNames[r]
			except:
				return None
	def getRowCount(self):
			return self._M.rows()
	def getColumnCount(self):
			return self._M.columns()

	def getValueAt(self, r, c):
			x=self._M.getQuick(r, c)
			return x

class Matrix(DenseDoubleMatrix2D):
	_M = None;   
	_name = 'data matrix'  
	type = 'var'
	columnNames = []
	rowNames = []
	varname = ''
	
	def __init__(self, M=None, N=None, v=None, sparse=None):
		#####printM.__class__
		self._M=self
		if isinstance(M, DenseDoubleMatrix2D):
			DenseDoubleMatrix2D.__init__(self,M.toArray());
		elif isinstance(M, Matrix):
			DenseDoubleMatrix2D.__init__(self,M.toArray())
		elif isinstance(M, int) and isinstance(N, int):
			if sparse:
				F = cern.colt.matrix.DoubleFactory2D.dense
			else:
				F = cern.colt.matrix.DoubleFactory2D.dense

			if v is None:
				DenseDoubleMatrix2D.__init__(self,F.make(int(M), int(N), 0).toArray());
			elif isinstance(v, int):
				DenseDoubleMatrix2D.__init__(self,F.make(M, N, v).toArray());
			elif isinstance(v, PyList):
				DenseDoubleMatrix2D.__init__(self,F.make(jarray.array(v, 'd'), 1).toArray())
			elif isinstance(v, PyString):
				DenseDoubleMatrix2D.__init__(self,F.random(M, N).toArray())
			else:
				DenseDoubleMatrix2D.__init__(self,v)		
		else:
				DenseDoubleMatrix2D.__init__(self,M)
		self._M=self
		self.columnNames=[]
		self.rowNames=[]
				
	def __sub__(A, B):
		
		ar=A.rows()-1;		
		ac=A.columns()-1;
		C = Matrix(ar, ac, 'r');

		if B is int:
			ar=A.rows()-1;		
			ac=A.columns()-1;
			for i in range(0,ar):
				for j in range(0,ac):
					C[i,j] = A[i,j].toArray() - B
			return C
		
		for i in range(0, ar):
			for j in range(0, ac):
				a = A[i,j].toArray()
				b = B[i,j].toArray()
				a=a[0]
				b=b[0]				
				C[i,j]=a[0]-b[0]
		return C;
		
	def __mul__(A, B):
			if isinstance(A, PyFloat) or isinstance(A, int):
				if isinstance(B._M, cern.colt.matrix.DoubleMatrix1D):
					f = cern.jet.math.DoubleMult
					B._M.assign(f.mult(A))
					return Matrix(B)
				else:
					raise "Matrix is not 1-D"
					return
			if isinstance(B, PyFloat) or isinstance(B, int):
				if isinstance(A._M, cern.colt.matrix.DoubleMatrix1D):
					f = cern.jet.math.DoubleMult
					A._M.assign(f.mult(B))
					return Matrix(A)
				else:
					raise "Matrix is not 1-D"
					return
			else:
				try:
					F = Algebra(0.0)
					C=F.mult(A._M, B._M)
					####print"in multiplication"
					return Matrix(C)
				except:
					raise PyValueException, "Inner dimension mismatch in matrix multiply.";
				 
	def __div__(A, B):
			###printsize(A)

			try:
				F = DoubleAlgebra();
				R = F.solve(A._M, B._M);
				return R;
			except (java.lang.IllegalArgumentException) , e :
				# check the error class types according to the matrix class so we can intelligently report the error.
				##printe.getMessage();
				return None;		
		
	def __repr__(self):
			return self._M.toString();
				
	def __str__(self):
			return self._M.toString();

	def __sz__(self):		
			if isinstance(self, Matrix):
				x=self._M.rows()-1;
				y=self._M.columns()-1;
				return (x, y);
			else:
				raise PyValueException, "Argument must be a matrix.";   
			   
	def __setitem__(self, idx, v=None):
			if v is None:
				raise PyValueException, "v is none"
			
			if isinstance(v, float):
				self.set(idx[0], idx[1], v);
				return;
			
			Y=idx[1];
			X=idx[0];
				
			if isinstance(X, PySlice):
				if X.start == None:
				   X=range(0, self._M.rows()-1)
			if isinstance(Y, PySlice):
				if Y.start == None:
				   Y=range(0, self._M.columns()-1)
			order=0;
			if isinstance(X,int):
				X=[X]
			if isinstance(Y,int):
				Y=[Y]
			if len(X)>len(Y):
				order=1;
			
			#print"the order is " , order	
			#print "value is ", v
			if order==0:
				y=0
				for q in Y:
						x=0
						for z in X: 
	   	   	   	   	   	   	if isinstance(v,PyInteger):
	   	   	   	   	   	   		self.set(z,q,v)
	   	   	   	   	   	   	else:
   	   	   	   	   	   			self.set(z, q, v.getQuick(x, y));
							x=x+1;
						y=y+1;
			else:
				x=0
				for z in X:					
						y=0;
						for q in Y:			 
	   	   	   	   	   	   	if isinstance(v,PyInteger):
	   	   	   	   	   	   		self.set(z,q,v)
	   	   	   	   	   	   	else:
								self.set(z, q, v.getQuick(x, y));
							y=y+1;
						x=x+1;
				return
								
	def __getslice__(self, i, j):

			if i.start != None:
				x=range(i.start, i.stop);
			else:
				x=range(0, self._M.rows())
			if j.start !=None:	
				y=range(j.start, j.stop)
			else:
				y=range(0, self._M.columns())
			
			return Matrix(self._M.viewSelection(x, y));

	def __getitem__(self, idx):

			x=idx[0];
			y=idx[1];
				
			
			if isinstance(x, PySlice):
				if x.start != None:
				   x=range(x.start, x.stop);
				else:
				   x=range(0, self._M.rows()-1)				   
		   
			if isinstance(y, PySlice):
				if y.start != None:
					y=range(y.start, y.stop);
				else:
					y=range(0, self._M.columns()-1)		 
			elif isinstance(y, PySlice):
				if y.start !=None:	
					y=range(y.start, y.stop)
				else:
					y=range(0, self._M.columns()-1)
			
			if isinstance(x,int):
				x=[x]
			if isinstance(y,int):
				y=[y]
				
			r = self._M.viewSelection(x, y);
			return Matrix(r.toArray())  # this is a specific element
			